package org.nobject.common.encrpt;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

/**
 * 加密工具
 *
 * @author bianrongjun
 * @version 1.0
 */
public class EncrptUtils {
	/** encodingChar */
	final static String encodingChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ ";
	
	/** 
	 * fromBase64
	 * @param source
	 */
	public static String fromBase64(String source) {
		if (source.length() % 4 != 0)
			throw new RuntimeException("valid Base64 codes have a multiple of 4 characters ");
		int numGroups = source.length() / 4;
		int numExtraBytes = source.endsWith("== ") ? 2 : (source.endsWith("= ") ? 1 : 0);
		byte[] targetBytes = new byte[3 * numGroups];
		byte[] sourceBytes = new byte[4];
		for (int group = 0; group < numGroups; group++) {
			for (int i = 0; i < sourceBytes.length; i++) {
				sourceBytes[i] = (byte) Math.max(0, encodingChar.indexOf(source.charAt(4 * group + i)));
			}
			convert4To3(sourceBytes, targetBytes, group * 3);
		}
		return new String(targetBytes, 0, targetBytes.length - numExtraBytes);
	}
	
	/**
	 * Returns the base 64 encoded equivalent of a supplied string.
	 * 
	 * @param source
	 *            the string to encode
	 */
	public static String toBase64(String source) {
		char[] sourceBytes = getPaddedBytes(source);
		int numGroups = (sourceBytes.length + 2) / 3;
		char[] targetBytes = new char[4];
		char[] target = new char[4 * numGroups];

		for (int group = 0; group < numGroups; group++) {
			convert3To4(sourceBytes, group * 3, targetBytes);
			for (int i = 0; i < targetBytes.length; i++) {
				target[i + 4 * group] = encodingChar.charAt(targetBytes[i]);
			}
		}

		int numPadBytes = sourceBytes.length - source.length();

		for (int i = target.length - numPadBytes; i < target.length; i++)
			target[i] = '=';
		return new String(target);
	}

	private static char[] getPaddedBytes(String source) {
		char[] converted = source.toCharArray();
		int requiredLength = 3 * ((converted.length + 2) / 3);
		char[] result = new char[requiredLength];
		System.arraycopy(converted, 0, result, 0, converted.length);
		return result;
	}

	private static void convert3To4(char[] source, int sourceIndex, char[] target) {
		target[0] = (char) (source[sourceIndex] >>> 2);
		target[1] = (char) (((source[sourceIndex] & 0x03) << 4) | (source[sourceIndex + 1] >>> 4));
		target[2] = (char) (((source[sourceIndex + 1] & 0x0f) << 2) | (source[sourceIndex + 2] >>> 6));
		target[3] = (char) (source[sourceIndex + 2] & 0x3f);
	}

	/**
	 * Returns the plaintext equivalent of a base 64-encoded string.
	 * 
	 * @param source
	 *            a base 64 string (which must have a multiple of 4 characters)
	 */
	public static String decode(String source) {
		if (source.length() % 4 != 0)
			throw new RuntimeException("valid Base64 codes have a multiple of 4 characters ");
		int numGroups = source.length() / 4;
		int numExtraBytes = source.endsWith("== ") ? 2 : (source.endsWith("= ") ? 1 : 0);
		byte[] targetBytes = new byte[3 * numGroups];
		byte[] sourceBytes = new byte[4];
		for (int group = 0; group < numGroups; group++) {
			for (int i = 0; i < sourceBytes.length; i++) {
				sourceBytes[i] = (byte) Math.max(0, encodingChar.indexOf(source.charAt(4 * group + i)));
			}
			convert4To3(sourceBytes, targetBytes, group * 3);
		}
		return new String(targetBytes, 0, targetBytes.length - numExtraBytes);
	}

	private static void convert4To3(byte[] source, byte[] target, int targetIndex) {
		target[targetIndex] = (byte) ((source[0] << 2) | (source[1] >>> 4));
		target[targetIndex + 1] = (byte) (((source[1] & 0x0f) << 4) | (source[2] >>> 2));
		target[targetIndex + 2] = (byte) (((source[2] & 0x03) << 6) | (source[3]));
	}
	
	/** 
	 * 转换为SHA1
	 * @param str
	 */
	public static String toSHA1(String str) {
		MessageDigest md = null;
		String strDes = null;
		byte[] bt = str.getBytes();
		try {
			md = MessageDigest.getInstance("SHA-1");
			md.update(bt);
			strDes = bytes2Hex(md.digest()); // to HexString
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
		return strDes;
	}
	
	/** 
	 * 转换为MD5
	 * @param str
	 */
	public static String toMD5(String str) {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
			byte[] results = md.digest(str.getBytes());
			return bytes2Hex(results);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
	
	/** 
	 * bytes2Hex
	 * @param bs
	 * @return
	 */
	private static String bytes2Hex(byte[] bs) {
		String des = "";
		String tmp = null;
		for (int i = 0; i < bs.length; i++) {
			tmp = (Integer.toHexString(bs[i] & 0xFF));
			if (tmp.length() == 1) {
				des += "0";
			}
			des += tmp;
		}
		return des;
	}


	public static void testKey(String[] args) throws Exception {
		String ptext = "he";

		for (int i = 0; i < 10; i++) {
			ptext += ptext;
		}

		// 获取公钥生成参数
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
		kpg.initialize(1024);
		KeyPair keyPair = kpg.genKeyPair();

		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

		// KeyPair keyPair=new

		System.out.println("公钥:" + publicKey);
		System.out.println("私钥:" + privateKey);
		System.out.println("公共码" + publicKey.getModulus().toString());

		byte[] ptexts = ptext.getBytes("UTF8");
		BigInteger m = new BigInteger(ptexts);
		BigInteger c = m.modPow(publicKey.getPublicExponent(), publicKey.getModulus());
		System.out.println("密文" + c);

		// System.out.println("d："+privateKey.getPrivateExponent());

		System.out.println("私密码" + privateKey.getModulus());

		BigInteger jm = c.modPow(privateKey.getPrivateExponent(), privateKey.getModulus());
		System.out.println("解码数据" + jm);

		byte[] mt = jm.toByteArray();

		System.out.print("解码结果:" + new String(mt, "UTF-8"));
		// for(int i=0;i<mt.length;i++){
		// System.out.print((char)mt[i]);
		// }
	}
	
	

}